#include "stdio.h"
#include "stdlib.h"
#include "stdint.h"
#include "string.h"


uint16_t halCommonCrc16( uint8_t byte, uint16_t crc  ) 
{
    crc = (crc >> 8) | (crc << 8); 
    crc ^= byte; 	
    crc ^= (crc & 0xff) >> 4; 	
    crc ^= (crc << 8) << 4; 	
    //[[ What I wanted is the following function: 	
    // crc ^= ((crc & 0xff) << 4) << 1; 	
    // Unfortunately the compiler does this in 46 cycles.  The next line of code 	
    // does the same thing, but the compiler uses only 10 cycles to implement it. 	
    //]] 	
    crc ^= ( (uint8_t) ( (uint8_t) ( (uint8_t) (crc & 0xff) ) << 5)) | ((uint16_t) ( (uint8_t) ( (uint8_t) (crc & 0xff)) >> 3) << 8); 	
    return crc; 
}

// CRC-32
uint32_t POLYNOMIAL = (0xEDB88320L);

uint32_t halCommonCrc32(uint8_t data, uint32_t accumulator) 
{ 	
    uint8_t jj;
    uint32_t previous; 	
    uint32_t oper; 	
    
    previous = (accumulator >> 8) & 0x00FFFFFFL; 	
    oper = (accumulator ^ data) & 0xFF; 	
    for (jj = 0; jj < 8; jj++) 	
    { 	
        oper = ((oper & 0x01) ? ((oper >> 1) ^ POLYNOMIAL) : (oper >> 1)); 	
    } 	
    return (previous ^ oper); 
}

void printusage(void)
{
    printf("Usage:\r\n");
    printf("        crc 16/32 file [poly 0xXXXXXXXX]\r\n");
}

int main(int argc,char *argv[])
{
    FILE *fs = NULL;
    uint8_t ch = 0;
    uint32_t crc = 0xffffffff;
    uint32_t filesize = 0;
    uint32_t i = 0;
    if(argc < 3)
    {    
        printusage();
        uint32_t dat = 0x12345678;
        unsigned char *j = 0;
        j = (unsigned char *)(&dat);
        printf("存储模式：");
        printf("0x12345678 -> 0:0x%02X 1:0x%02X 2:0x%02X 3:0x%02X \r\n",j[0],j[1],j[2],j[3]);//	0X44 0X33 0X22 0X11 小端存储 
        printf("CRC32 示例：\r\n");
        for(i = 0;i < 4;i ++)
            crc = halCommonCrc32(j[i],crc);
        printf("原值：%#X　CRC32(%#X) %#X\r\n",dat,POLYNOMIAL,crc);
        return 0;
    }
    if((argc == 5) && strstr(argv[3],"poly"))
    {
        POLYNOMIAL = strtol(argv[4],NULL,16);
    }
    if((fs = fopen(argv[2],"r")) == NULL)
    {
        printf("file read error\r\n");
        return 0;
    }
    fseek(fs,0,SEEK_END);
    filesize = ftell(fs);
    fseek(fs,0,SEEK_SET);
    if(atoi(argv[1]) == 16)
    {
        do
        {
            ch = fgetc(fs);
            crc = halCommonCrc16(ch,crc);
            i ++;
        } while(i < filesize);
    
    }
    else if(atoi(argv[1]) == 32)
    {
        do
        {
            ch = fgetc(fs);
            crc = halCommonCrc32(ch,crc);
            i ++;
        } while(i < filesize); 
    }
    else
    {
        printf("file read error\r\n");
        return 0;
    }

    fclose(fs);
    printf("%#X %d %#X %s\r\n",crc,filesize,POLYNOMIAL,argv[2]);

    return 0;
}


#define	CRC32_MASK	((unsigned long)0xFFFFFFFF)
unsigned long Crc32Table[256];

void MakeCrc32Table()
{
	unsigned long i,j;
	unsigned long crc;
	for (i = 0; i < 256; i ++)
	{
		crc = i<<24;
		for(j = 0; j < 8; j ++)
		{
			if (crc & 0x80000000)
			{
				crc = (crc << 1) ^ 0x4C11DB7;
			}
			else
			{
				crc <<= 1;
			}
		}
		Crc32Table[i] = crc&CRC32_MASK;
	}
}

unsigned long  CalcCrc32(const unsigned char* data, unsigned long size)
{
	unsigned long crc = CRC32_MASK;
	while(size--)
	{
		crc = (crc << 8) ^ Crc32Table[ ((crc >> (32-8)) & 0xFF) ^ *data++]; 
	}
	crc ^= CRC32_MASK;
	return crc;
}


void MakeCrc32TableRev()
{
	unsigned long i,j;
	unsigned long crc;
	for (i = 0; i < 256; i ++)
	{
		crc = i;
		for(j = 0; j < 8; j ++)
		{
			if(crc & 0x01)
			{
				crc = (crc >> 1) ^ 0xEDB88320;
			}
			else
			{
				crc >>= 1;
			}
		}
		Crc32Table[i] = crc&CRC32_MASK;
	}
}

unsigned long  CalcCrc32Rev(const unsigned char* data, unsigned long size)
{
	unsigned long crc = CRC32_MASK;
	while(size--)
	{
		crc = (crc >> 8) ^ Crc32Table[ (crc & 0xFF) ^ *data++]; 
	}
	crc ^= CRC32_MASK;
	return crc;
}




